﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TekaMUD.Engine.Behaviour;

namespace TekaMUD.Engine.Blocks
{
	/// <summary>
	/// Implements a container of game objects. The internal container is implemented with a List<GameObject>
	/// due to the fact that in most cenarios the amount of objects stored will be small. 
	/// </summary>
	/// <remarks>This class is thread safe</remarks>
	public class ObjectContainer : GameObject
	{
		private List<GameObject> _contents = new List<GameObject>();

		/// <summary>
		/// The maximum number of items this container may hold.
		/// </summary>
		public uint MaximumItems { get; private set; }

		public ObjectContainer(uint max)
		{
			MaximumItems = max;
		}

		/// <summary>
		/// Returns the current amount of items stored in the container.
		/// </summary>
		public int Quantity
		{
			get
			{
				lock (SyncRoot)
				{
					return _contents.Count;
				}
			}
		}

		/// <summary>
		/// Returns an array of the current contents of the container.
		/// </summary>
		public GameObject[] Contents
		{
			get
			{
				lock (SyncRoot)
				{
					return _contents.ToArray();
				}
			}
		}

		public List<GameObject> GetByType(Type targetType)
		{
			List<GameObject> ret = new List<GameObject>();

			lock (SyncRoot)
				foreach (GameObject go in _contents)
					if (go.GetType().Equals(targetType))
						ret.Add(go);

			return ret;
		}

		/// <summary>
		/// Add the given GameObject to the container. 
		/// </summary>
		/// <returns>True in case the operation was sucessfull, false otherwise.</returns>
		public bool Store(GameObject go)
		{
			lock (SyncRoot)
			{
				if(go is IUncountable)
					foreach (GameObject sgo in _contents)
						if (go.GetType().Equals(sgo.GetType()))
						{
							(sgo as IUncountable).Quantity += (go as IUncountable).Quantity;
							return true;
						}

				if (_contents.Count >= MaximumItems)
					return false;

				_contents.Add(go);

			}

			return true;
		}

		/// <summary>
		/// Tries to remove the specified object from the container in a thread safe manner.
		/// </summary>
		/// <returns>true in case the operation was sucessfull, false in case the object is no longer in the container.</returns>
		public bool TryAndRemove(GameObject go)
		{
			lock (SyncRoot)
			{
				if (_contents.Contains(go))
				{
					_contents.Remove(go);
					return true;
				}

				return false;

			}
		}

		/// <summary>
		/// Checks if the specified object is still in the container in a thread safe manner.
		/// </summary>
		/// <returns>true in case the operation was sucessfull, false in case the object is no longer in the container</returns>
		public bool Test(GameObject go)
		{
			lock (SyncRoot)
			{
				if (_contents.Contains(go))
					return true;
				else
					return false;
			}
		}
	}
}
